科技遐想阁

欢迎您来到“科技遐想阁”,一个汇聚技术与非技术文章的丰富平台。

1
2
3
4
5
6
git checkout --orphan latest_branch
git add -A
git commit -am "init"
git branch -D master
git branch -m master
git push -f origin master

Docker 相关安装

阿里的linux需要这个 (新版本可能不用了)

1
dnf -y install dnf-plugin-releasever-adapter --repo alinux3-plus

DOCKER 安装说明

官方文档

整理如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

yum install -y yum-utils

yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

yum install -y docker-ce docker-ce-cli containerd.io



systemctl enable docker.service
systemctl start docker

Docker Compose 安装说明

官方文档

整理如下:

1
2
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Dockerfile 中的 ADDCOPY 两个指令都用于将文件从主机复制到 Docker 镜像中,但它们之间有一些关键区别:

  1. 复制源文件类型:

    • ADD:可以复制本地文件、远程文件(通过URL)、以及解压缩文件(会自动解压缩)到镜像中。
    • COPY:只能复制本地文件或目录到镜像中。不支持远程文件或自动解压缩。
  2. 目标路径处理:

    • ADD:如果目标路径不存在,会尝试创建目录。如果复制的是压缩文件,会自动解压到目标路径。
    • COPY:要求目标路径必须事先存在,不会执行自动解压缩操作。
  3. 建议用途:

    • 一般情况下,如果你只需要将本地文件或目录复制到镜像中,并且不需要复制远程文件或自动解压缩,建议使用 COPY,因为它更明确和简单。
    • 如果需要复制远程文件或者要求自动解压缩,可以使用 ADD

示例使用 COPY

1
COPY ./sourcefile.txt /destination/

示例使用 ADD

1
ADD https://example.com/file.tar.gz /destination/

总的来说,选择使用哪个指令取决于你的需求和是否需要额外的功能。通常情况下,为了保持 Dockerfile 的清晰和简单,建议使用 COPY,除非你明确需要 ADD 的额外功能。

Docker Compose 中的 restart 选项用于定义容器在退出或停止后应该如何重启。以下是一些常见的 restart 参数及其含义:

  1. **”no”**(默认值):表示不会自动重启容器。如果容器退出或停止,它将保持在停止状态,不会自动重新启动。

  2. **”always”**:表示无论容器如何退出,都会自动重启。这意味着如果容器崩溃或被手动停止,Compose 会尝试自动重新启动它。

  3. **”on-failure”**:表示只有在容器以非零退出状态(即失败)退出时才会自动重启。如果容器以零退出状态正常停止,则不会自动重新启动。

  4. **”unless-stopped”**:表示容器会自动重启,除非你手动停止它。这个选项在大多数情况下是持久的,只有在你显式停止容器时才会停止。

  5. **”on-abnormal”**:表示只有在容器以非正常方式退出时(例如,由于主机上的内存不足)才会自动重启。这个选项通常用于处理异常情况。

  6. **”on-reboot”**:表示容器会在宿主机重新启动时自动重启。这可以确保容器在宿主机重启后保持运行状态。

  7. “always” 和 “unless-stopped” 组合:可以将这两个选项组合在一起,以确保容器在退出时自动重启,并在手动停止时也重启。例如:restart: always 会一直重启容器,而 restart: unless-stopped 会在容器崩溃时重启,但在手动停止时不会重启。

这些选项可以根据你的需求来选择,以确保容器在各种情况下的行为是符合预期的。不同的应用场景可能需要不同的重启策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import os
import datetime
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import openai
import time

# 在这里设置你的 OpenAI API 密钥
openai.api_key = 'sk-rCJsSuapC0JknFaaxxxxxxxxxxxxxxxxx'

# 获取当前日期
current_date = datetime.date.today()

# 创建文件夹路径
folder_path = os.path.join("C:/桌面/每日新闻", str(current_date))

# 创建文件夹
os.makedirs(folder_path, exist_ok=True)

# 创建文件路径
file_path = os.path.join(folder_path, "CNN新闻.txt")

url = "https://edition.cnn.com/"

response = requests.get(url)
html_content = response.content

soup = BeautifulSoup(html_content, "html.parser")

container = soup.find(class_="container__field-links container_ribbon__field-links")

if container:
links = container.find_all("a")

# 打开文件并写入内容
with open(file_path, "w", encoding="utf-8") as file:
# 遍历链接并访问每个链接
for link in links:
href = link.get("href")
full_link = urljoin(url, href)

try:
response = requests.get(full_link)
response.raise_for_status() # 检查是否有异常状态码
html = BeautifulSoup(response.content, "html.parser")

articles = html.find_all(class_="article__content")

if articles is None:
continue

content = ' '.join([article.get_text() for article in articles])

user_input = f"摘要以下文章内容:\n{content}\n摘要:"

# 控制请求频率
time_between_requests = 60 / 30 # 3 RPM
time.sleep(time_between_requests)

summary_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": user_input}
],
temperature=1,
max_tokens=256,
)

summary = summary_response.choices[0].message['content'].strip()

# 将摘要写入文件
file.write(summary + "\n\n")

# 打印摘要
print(summary)
print('---------------------------------------------------------------------------------')

except requests.RequestException as e:
print(f"请求出错:{str(e)}")

print("文件写入完成!")

将 Git 的默认分支从 “master” 更改为 “main” 是一项旨在促进包容性和反对历史上的种族主义和歧视的举措。下面详细展开一些背景和原因:

  1. 历史背景:在过去的几十年中,”master” 这个词汇在一些英语-speaking 地区被用来描述奴隶制和种族主义的历史。尽管 “master” 在软件开发上一直是一个常用的术语,但一些人认为它可能会引发不适当的联想,因此有必要寻找更中性的替代方案。

  2. 社会意识的提高:随着时间的推移,社会对于不平等和歧视问题的意识逐渐提高。技术社区也逐渐认识到自己在促进包容性和多元化方面的责任。这一趋势使得一些开源项目和开发者开始审查他们的术语和约定,以确保它们不会传递不适当或冒犯性的信息。

  3. 倡导者的声音:一些倡导者和开源社区的成员呼吁将 “master” 分支更名为更中性的名称。他们认为这样的更改可以传递一个积极的信息,表明技术社区关心包容性和反对历史上的不平等。

  4. 平台支持:一些主要的代码托管平台,如 GitHub、GitLab 和 Bitbucket,已经采取了行动,支持将默认分支名称更改为 “main”。这些平台的决策对许多开源项目产生了影响,鼓励它们采用新的默认分支名称。

  5. 技术社区的改变:技术社区逐渐变得更加多元化,不同背景和文化的人们参与其中。改变默认分支名称是一种信号,表明技术社区愿意迎接各种背景的人,并创建一个更加包容和多元化的环境。

综上所述,将 Git 默认分支名称从 “master” 更改为 “main” 是一个符合现代社会和技术社区的举措,旨在创造一个更开放、包容和多元化的编程环境。这个更改强调了技术社区的关注点,包括反对历史上的不平等,并表明社区愿意采取积极行动来实现这些目标。这个决策并没有改变 Git 的核心功能,但它传达了一个重要的信息,即技术社区关心社会和文化问题,并致力于做出积极的改变。

Docker 镜像制作是将一个应用程序和其依赖项打包到一个可执行的文件系统中的过程。下面是制作 Docker 镜像的基本步骤:

  1. 创建 Dockerfile: Dockerfile 是一个文本文件,包含了构建镜像所需的指令和配置。你可以使用文本编辑器创建一个 Dockerfile。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 使用一个基础镜像
    FROM ubuntu:latest

    # 设置工作目录
    WORKDIR /app

    # 复制应用程序到镜像中
    COPY . .

    # 安装应用程序的依赖项
    RUN apt-get update && apt-get install -y <dependencies>

    # 设置容器启动时执行的命令
    CMD ["<command>", "<arguments>"]
  2. 构建镜像: 使用 docker build 命令来根据 Dockerfile 构建镜像。在终端中进入 Dockerfile 所在的目录,然后运行:

    1
    docker build -t my-image-name .

    其中 -t 参数用来指定镜像的名称和标签,. 表示使用当前目录中的 Dockerfile。

  3. 等待构建完成: Docker 将根据 Dockerfile 中的指令执行构建过程。这可能需要一些时间,取决于镜像的大小和指令的复杂性。

  4. 使用新建的镜像: 构建完成后,你可以使用 docker run 命令来创建一个基于该镜像的容器并运行应用程序:

    1
    docker run my-image-name

这只是一个简单的示例,实际的 Dockerfile 可能会更加复杂,取决于你的应用程序和依赖项。在制作镜像时,你可以根据应用程序的要求来添加更多的指令,如安装软件包、配置环境变量等。

请注意,制作 Docker 镜像需要一定的 Docker 知识和命令行操作经验。如果你是新手,建议查阅 Docker 的官方文档以获取更详细的指导。

1
2
3
4
5
6
7
8
9
10
11
12
apt-get update \
&& apt-get install -y ca-certificates curl gnupg \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \
&& chmod a+r /etc/apt/keyrings/docker.gpg \
&& echo "deb [arch=\"$(dpkg --print-architecture)\" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \"$(. /etc/os-release && echo \"$VERSION_CODENAME\")\" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \
&& docker run hello-world

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

另外附上官网教程:https://docs.docker.com/engine/install/ubuntu/

常量与变量

  1. 下列代码的输出是:
1
2
3
4
5
6
7
8
9
10
func main() {
const (
a, b = "golang", 100
d, e
f bool = true
g
)
fmt.Println(d, e, g)
}

答案

golang 100 true

在同一个 const group 中,如果常量定义与前一行的定义一致,则可以省略类型和值。编译时,会按照前一行的定义自动补全。即等价于

1
2
3
4
5
6
7
8
9
func main() {
const (
a, b = "golang", 100
d, e = "golang", 100
f bool = true
g bool = true
)
fmt.Println(d, e, g)
}
  1. 下列代码的输出是:
1
2
3
4
5
6
7
8
func main() {
const N = 100
var x int = N

const M int32 = 100
var y int = M
fmt.Println(x, y)
}
答案

编译失败:cannot use M (type int32) as type int in assignment

Go 语言中,常量分为无类型常量和有类型常量两种,const N = 100,属于无类型常量,赋值给其他变量时,如果字面量能够转换为对应类型的变量,则赋值成功,例如,var x int = N。但是对于有类型的常量 const M int32 = 100,赋值给其他变量时,需要类型匹配才能成功,所以显示地类型转换:

1
var y int = int(M)
  1. 下列代码的输出是:
1
2
3
4
5
func main() {
var a int8 = -1
var b int8 = -128 / a
fmt.Println(b)
}
答案

-128

int8 能表示的数字的范围是 [-2^7, 2^7-1],即 [-128, 127]。-128 是无类型常量,转换为 int8,再除以变量 -1,结果为 128,常量除以变量,结果是一个变量。变量转换时允许溢出,符号位变为1,转为补码后恰好等于 -128。

对于有符号整型,最高位是是符号位,计算机用补码表示负数。补码 = 原码取反加一。

例如:

1
2
3
4
5
6
7
8
9
-1 :  11111111
00000001(原码) 11111110(取反) 11111111(加一)
-128:
10000000(原码) 01111111(取反) 10000000(加一)

-1 + 1 = 0
11111111 + 00000001 = 00000000(最高位溢出省略)
-128 + 127 = -1
10000000 + 01111111 = 11111111
  1. 下列代码的输出是:
1
2
3
4
5
func main() {
const a int8 = -1
var b int8 = -128 / a
fmt.Println(b)
}
答案

编译失败:constant 128 overflows int8

-128 和 a 都是常量,在编译时求值,-128 / a = 128,两个常量相除,结果也是一个常量,常量类型转换时不允许溢出,因而编译失败。

作用域

  1. 下列代码的输出是:
1
2
3
4
5
6
7
8
9
10
func main() {
var err error
if err == nil {
err := fmt.Errorf("err")
fmt.Println(1, err)
}
if err != nil {
fmt.Println(2, err)
}
}
答案

1 err

:= 表示声明并赋值,= 表示仅赋值。

变量的作用域是大括号,因此在第一个 if 语句 if err == nil 内部重新声明且赋值了与外部变量同名的局部变量 err。对该局部变量的赋值不会影响到外部的 err。因此第二个 if 语句 if err != nil 不成立。所以只打印了 1 err

defer 延迟调用

  1. 下列代码的输出是:
1
2
3
4
5
6
7
8
9
10
11
12
type T struct{}

func (t T) f(n int) T {
fmt.Print(n)
return t
}

func main() {
var t T
defer t.f(1).f(2)
fmt.Print(3)
}
答案

132

defer 延迟调用时,需要保存函数指针和参数,因此链式调用的情况下,除了最后一个函数/方法外的函数/方法都会在调用时直接执行。也就是说 t.f(1) 直接执行,然后执行 fmt.Print(3),最后函数返回时再执行 .f(2),因此输出是 132。

  1. 下列代码的输出是:
1
2
3
4
5
6
7
8
func f(n int) {
defer fmt.Println(n)
n += 100
}

func main() {
f(1)
}
答案

1

打印 1 而不是 101。defer 语句执行时,会将需要延迟调用的函数和参数保存起来,也就是说,执行到 defer 时,参数 n(此时等于1) 已经被保存了。因此后面对 n 的改动并不会影响延迟函数调用的结果。

  1. 下列代码的输出是:
1
2
3
4
5
6
7
func main() {
n := 1
defer func() {
fmt.Println(n)
}()
n += 100
}
答案

101

匿名函数没有通过传参的方式将 n 传入,因此匿名函数内的 n 和函数外部的 n 是同一个,延迟执行时,已经被改变为 101。

  1. 下列代码的输出是:
1
2
3
4
5
6
7
8
func main() {
n := 1
if n == 1 {
defer fmt.Println(n)
n += 100
}
fmt.Println(n)
}
答案
1
2
101
1

先打印 101,再打印 1。defer 的作用域是函数,而不是代码块,因此 if 语句退出时,defer 不会执行,而是等 101 打印后,整个函数返回时,才会执行。